package app.modules 
{
	import app.AppModel;
	import app.modules.ChooseAttribModel;
	import app.modules.RadioButtonInfo;
	import flash.display.DisplayObject;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.geom.Rectangle;
	import flash.text.TextField;
	import flash.utils.Dictionary;
	import furnitures.FurnitureModel;
	import gui.buttons.RadioButton;
	import gui.factory.StyleFactory;
	import gui.NumStepper;
	import gui.PositionInfo;
	import resources.Images;
	import utils.Converter;
	import utils.ErrorsCollector;
	import utils.Logger;
	/**
	 * ...
	 * @author Dmitriy Gaiduk
	 */
	
	/**
	 * Представляет модуль выбора атрибутов мебели: размеры, сторона левый/правый, со стеклом/без стекла
	 * Меняет значение AppModel.furnitureForAdd
	 * Разделяется на секции. Например секции выбора атрибутов для разных радиусных шкафов
	 * Схема работы
	 * 1. При добавлении на Stage вызывается метод initModule() - добавляются элементы интерфейса
	 * 2. При изменении значения интерактивного объекта вызывается onAttributeChanged()
	 * 3. onAttributeChanged() меняет секцию при необходимости и вызывает метод makeFurnitureByAttribs()
	 * 4. Метод makeFurnitureByAttribs() считывает значения выбранных атрбутов и составляет ID модели
	 * 	 Далее ищется модель мебели по данному ID в AppModel.furnituresDict. Если модель найдена, выставляются
	 * 	 дополнительные параметры (левый/правый, со стеклом). 
	 * 	 После как модель готова, меняется значение AppModel.furnitureForAdd
	 * 	
	 */
	
	public class ModuleChooseAttrib extends Sprite
	{
		private var _rightSide:Boolean;
		private var _withGlass:Boolean;
		private var _furnWidth:Number;
		private var _furnHeight:Number;
		private var _chooseAttribModel:ChooseAttribModel;
		private var _radioButtons:Vector.<RadioButton>;
		private var _numSteppers:Vector.<NumStepper>;
		private var _moduleWidth:Number;
		private var _moduleHeight:Number;
		private var _header:String;
		private var _currentSection:String = "";
		private var _prefixFurnitureDict:Dictionary; // prefix name for sections
		
		private var _sectionDict:Dictionary;
		private var _model:AppModel;
		
		/**
		 * 
		 * @param	model модель приложения
		 * @param	chooseAttribModel модель модуля атрибутов
		 * @param	header Заголовок
		 */
		public function ModuleChooseAttrib(model:AppModel, chooseAttribModel:ChooseAttribModel, header:String) 
		{
			_model = model;
			_chooseAttribModel = chooseAttribModel;
			if (header != null)
			{
				_header = header;
			}else
			{
				_header = "";
			}
			addEventListener(Event.ADDED_TO_STAGE, handleAddedToStage);
		}
		
		private function handleAddedToStage(e:Event):void 
		{
			removeEventListener(Event.ADDED_TO_STAGE, handleAddedToStage);
			initModule();
		}
		
		private function initModule():void 
		{
			// adjust module style
			_moduleWidth = StyleFactory.RIGHT_COLUMN_WIDTH;
			_moduleHeight = StyleFactory.CHOOSE_ATTRIB_MODULE_HEIGHT;
			this.y = StyleFactory.CHOOSE_ATTRIB_MODULE_Y;
			this.x = 100;
			_radioButtons = new Vector.<RadioButton>();
			_sectionDict = new Dictionary();
			
			var sectionIndex:int = 0;
			var pos:PositionInfo;
			// set header
			var txtHeader:TextField = new TextField();
			txtHeader.text = _header;
			StyleFactory.setTextStyle(txtHeader, StyleFactory.STYLE_TXT_CHOOSE_ATTRIB_HEADER);
			pos = new PositionInfo();
			pos.align = PositionInfo.ALIGN_CENTR_X;
			pos.posY = 0;
			txtHeader.x = pos.getPosX(this.width, txtHeader.width);
			txtHeader.y = pos.getPosY(this.height, txtHeader.height);
			addChild(txtHeader);
				_numSteppers  = new Vector.<NumStepper>();
			// read buttons
			_prefixFurnitureDict = new Dictionary();
			for each(var section:ChooseSectionInfo in _chooseAttribModel.sections)
			{
				var groupPrefix:String = "section" + sectionIndex + "_";
				_prefixFurnitureDict[groupPrefix.substr(0, groupPrefix.length - 1)] = section.furnitureID;
				_sectionDict[groupPrefix.substr(0, groupPrefix.length - 1)] = section;
				// add preview
				if (section.preview != null && section.preview.length > 0)
				{
					var preview:DisplayObject = Images.getInstance().getImage(section.preview);
					if (preview != null)
					{
						if (section.previewPos == null)
						{
							section.previewPos = new PositionInfo();
						}
						preview.x = section.previewPos.posX;
						preview.y = section.previewPos.posY;
						addChild(preview);
					}
				}
				
				// add radio buttons
				for each(var radBtnInfo:RadioButtonInfo in section.radioButtons)
				{
					var radBtn:RadioButton = new RadioButton();
					//radBtn.groupName = groupPrefix + getGroupeName(radBtnInfo.type);
					radBtn.groupName = groupPrefix + radBtnInfo.type;
					_radioButtons.push(radBtn);
					radBtn.label = radBtnInfo.title;
					StyleFactory.setRadioButtonStyle(radBtn, StyleFactory.STYLE_RB_CHOOSE_ATTRIB);
					radBtn.textField.width = radBtnInfo.textWidth;
					radBtn.validateNow();
					var rbRect:Rectangle = radBtn.getBoundRectComponent();
					 pos= radBtnInfo.position.clone();
					radBtn.x = pos.getPosX(this.width, rbRect.width);
					radBtn.y = pos.getPosY(this.height, rbRect.height);
					addChild(radBtn);
					radBtn.value = radBtnInfo;
					radBtn.addEventListener(Event.CHANGE, handleRadioButtonChange);
				}
				
				// add titles
				for each(var textInfo:TitleInfo in section.titles)
				{
					var txt:TextField = new TextField();
					txt.text = textInfo.text;
					StyleFactory.setTextStyle(txt, StyleFactory.STYLE_TXT_CHOOSE_ATTRIB);
					 pos = textInfo.position.clone();
					txt.x = pos.getPosX(this.width, txt.width);
					txt.y = pos.getPosY(this.height, txt.height);
					addChild(txt);
				}
				
				// add numericsteppers
				for each(var numstepInfo:NumStepperInfo in section.numSteppers)
				{
					var numStepper:NumStepper = new NumStepper(numstepInfo.title);
					StyleFactory.setNumStepStyle(numStepper, StyleFactory.NUM_STEP_FURNITURES_BOTTOM);
					if (numstepInfo.values != null)
					{
						numStepper.values = new Vector.<String>();
						// copy
						for each(var valStr:String in numstepInfo.values)
						{
							numStepper.values.push(valStr);
						}
					}else
					{
						numStepper.min = numstepInfo.min;
						numStepper.max = numstepInfo.max;
						numStepper.step = numstepInfo.step;
						numStepper.valueNum = numstepInfo.min;
					}
					numStepper.tag = numstepInfo;
					numStepper.groupeName = groupPrefix;
					_numSteppers.push(numStepper);
					numStepper.invalidateNow();
					//var numstepBounds:Rectangle = numStepper.geComponentBounds();
					numStepper.x = numstepInfo.position.getPosX(width, numStepper.width);
					numStepper.y = numstepInfo.position.getPosY(height, numStepper.height);
					numStepper.addEventListener(Event.CHANGE, handleNumStepChange);
					addChild(numStepper);
					numStepper.invalidateNow();
				}
				
				if (sectionIndex == 0)
				{
					_currentSection = getSection(groupPrefix);
					setupSection(_currentSection);
				}
				sectionIndex++;
			}
			if (sectionIndex > -1)
			{
				onAttributeChanged("section0");
			}else
			{
				handleError("No sections");
			}
		}
		
		private function handleNumStepChange(e:Event):void 
		{
			var numStepper:NumStepper = e.currentTarget as NumStepper;
			if (numStepper != null)
			{
				var numStepperSection:String = getSection(numStepper.groupeName);
				onAttributeChanged(numStepperSection);
				/*if (numStepperSection == _currentSection)
				{
					if (_model.furnitureForAdd != null)
					{
						adjustFurnitureModelByNumStep(_model.furnitureForAdd, numStepper);
					}else
					{
						
					}
				}*/
				//log("num step value: " + numStepper.valueString);
				
			}else
			{
				handleError("Numstepper change null");
			}
			
		}
		
		
		

		
		private function onAttributeChanged(sectionName:String):void
		{
			invalidateSections(sectionName);
			//_model.furnitureForAdd  = makeFurniture(_currentSection);
			if (_currentSection != sectionName)
			{
				setupSection(sectionName);
			}
			_currentSection = sectionName;
			//_model.furnitureForAdd = makeFurniture(_currentSection); 
			_model.furnitureForAdd = makeFurnitureByAttribs(_currentSection); 
		}
		
		private function handleRadioButtonChange(e:Event):void 
		{
			var radBtn:RadioButton = e.currentTarget as RadioButton;
			if (radBtn != null)
			{
				if (!radBtn.selected)
				{
					return;
				}
				var radBtnInfo:RadioButtonInfo = radBtn.value as RadioButtonInfo;
				if (radBtnInfo != null)
				{
					/*trace("Selected groupe: " + radBtn.groupName + 
							" type: " + radBtnInfo.type + " selected value: " + radBtnInfo.value);
					trace("Section: " + getSection(radBtn.groupName) + " type: " + getType(radBtn.groupName));
					trace("===============");*/
					//trace("Button: " + radBtn.label + " selected: " + );
					var sectionSelected:String = getSection(radBtn.groupName);
					onAttributeChanged(sectionSelected);
					
				}else
				{
					handleError("Selected radio button value is NULL: " + e.currentTarget);
				}
			}else
			{
				handleError("Selected radio button is NULL: " + e.currentTarget);
			}
		}
		
		private function invalidateSections(section:String):void 
		{
			for each (var radBtn:RadioButton in _radioButtons)
			{
				if (radBtn.selected)
				{
					if (getSection(radBtn.groupName) != section)
					{
						radBtn.selected = false;
					}
				}
			}
		}
		
	
		private function getSection(groupeName:String):String
		{
			var sectionRegExp:RegExp = /section[0-9]*/g;
			var arrMatch:Array = groupeName.match(sectionRegExp);
			if ((arrMatch != null) && (arrMatch.length > 0))
			{
				return  arrMatch[0];
			}
			return null;
		}
		
		private function getType(groupeName:String):String
		{
			var typeRegExp:RegExp = /_.*/g;
			var arrMatch:Array = groupeName.match(typeRegExp);
			if ((arrMatch != null) && (arrMatch.length > 0))
			{
				var str:String =  arrMatch[0];
				if (str.length > 0)
				{
					str = str.substr(1, str.length -1);
				}
				return str;
			}
			return null;
		}
		
		private function adjustFurnitureModelByNumStep(furn:FurnitureModel, 
							numStepper:NumStepper):void 
		{
			var numStepInfo:NumStepperInfo = numStepper.tag as NumStepperInfo;
			if (numStepInfo == null)
			{
				handleError("Numstepper info null");
				return;
			}
			switch(numStepInfo.type)
			{
				case TargetProperty.HEIGHT:
						furn.furnitureHeight = numStepper.valueNum;
					break;
				case TargetProperty.WIDTH:
						furn.furnitureWidth = numStepper.valueNum;
					break;
				default:
						handleError("Unknow Numstepper type");
					break;
			}
		}
		
		private function adjustAttributesByNumStep(attrib:FurnitureAttributes, 
													numStepper:NumStepper):void 
		{
			
			var numStepInfo:NumStepperInfo = numStepper.tag as NumStepperInfo;
		
			if (numStepInfo == null)
			{
				handleError("Numstepper info null");
				return;
			}
			
			if (numStepper.valueString == null)
			{
				log("Numstepper value null");
				return;
			}
		
			switch(numStepInfo.type)
			{
				case TargetProperty.HEIGHT:
						attrib.height = numStepper.valueString;
					break;
				case TargetProperty.WIDTH:
						
						attrib.width = numStepper.valueString;
					break;
				default:
						handleError("Unknow Numstepper type");
					break;
			}
		}
		
		private function adjustFurnitureAttribs(furnAttrib:FurnitureAttributes, radBtn:RadioButton):void 
		{
			var radBtnInfo:RadioButtonInfo = radBtn.value as RadioButtonInfo;
			if (radBtnInfo == null)
			{
				handleError("adjustFurnitureAttribs: info NULL");
				return;
			}
			var type:String = getType(radBtn.groupName);
			switch(radBtnInfo.type)
			{
				case TargetProperty.HEIGHT:
						furnAttrib.height = radBtnInfo.value.toString();
					break;
				case TargetProperty.WIDTH:
						furnAttrib.width = radBtnInfo.value.toString();
					break;
				case TargetProperty.SIDE:
						furnAttrib.side = radBtnInfo.value.toString();
					break;
				case TargetProperty.EXTRA:
						furnAttrib.extra = radBtnInfo.value.toString();;
					break;
			}	
		}
		
		
		private function adjustFurnitureModel(furn:FurnitureModel, radBtn:RadioButton):void 
		{
			var radBtnInfo:RadioButtonInfo = radBtn.value as RadioButtonInfo;
			if (radBtnInfo == null)
			{
				handleError("adjustFurnitureModel info NULL");
				return;
			}
			var type:String = getType(radBtn.groupName);
			switch(radBtnInfo.type)
			{
				case TargetProperty.HEIGHT:
						furn.furnitureHeight = Converter.getNumberFromStr(radBtnInfo.value.toString(), furn.furnitureHeight,
													"Module attrib height NaN" + radBtnInfo.value, false);
					break;
				case TargetProperty.WIDTH:
						furn.furnitureWidth = Converter.getNumberFromStr(radBtnInfo.value.toString(), furn.furnitureWidth,
													"Module attrib width NaN" + radBtnInfo.value, false);
					break;
				case TargetProperty.SIDE:
						furn.side = radBtnInfo.value.toString();
						
					break;
				case TargetProperty.EXTRA:
						furn.extra = radBtnInfo.value.toString();
					break;
			}	
		}
		
		private function makeFurnitureByAttribs(section:String):FurnitureModel
		{
			// id furniture: [prefix]#[height]-[width]
			
			var sectionInfo:ChooseSectionInfo = _sectionDict[section] as ChooseSectionInfo;
			if (sectionInfo == null)
			{
				handleError("sectionInfo null. section: " + section);
				return null;
			}
			
			var furnID:String = sectionInfo.idPrefix;
			var furnitureAttrib:FurnitureAttributes = new FurnitureAttributes();
			furnitureAttrib.side = FurnitureModel.SIDE_RIGHT;
			// setup default values
			furnitureAttrib.width = sectionInfo.defWidth;
			furnitureAttrib.height = sectionInfo.defHeight;
			
			// setup by radiobuttons
			for each (var radBtn:RadioButton in _radioButtons)
			{
				if (radBtn.selected)
				{
					adjustFurnitureAttribs(furnitureAttrib, radBtn);
				}
			}
		
			// setup by numeric stepper
			for each (var numStepper:NumStepper in _numSteppers)
			{
				if (getSection(numStepper.groupeName) == _currentSection)
				{
					adjustAttributesByNumStep(furnitureAttrib, numStepper);
				}
			}
			
			// make full name for id
			furnID += "#";
			furnID += furnitureAttrib.height;
			furnID += "-";
			furnID += furnitureAttrib.width;
			
			var furnModel:FurnitureModel = _model.furnituresDict[furnID] as FurnitureModel;
			if (furnModel == null)
			{
				log("Frutniture not found; ID: " + furnID);
				return null;
			}
			// clone - make own model
			furnModel = furnModel.clone();
			furnModel.side = furnitureAttrib.side;
			furnModel.extra = furnitureAttrib.extra;
			return furnModel;
		}
		
		private function makeFurniture(sectionName:String):FurnitureModel
		{
			var furnID:String = _prefixFurnitureDict[sectionName];
			var furn:FurnitureModel = (_model.furnituresDict[furnID] as FurnitureModel).clone();
			if (furn == null)
			{
				handleError("Can't finde furniture ID: " + furnID + " section name: " + sectionName);
				return null;
			}
			
			for each (var radBtn:RadioButton in _radioButtons)
			{
				if (radBtn.selected)
				{
					adjustFurnitureModel(furn, radBtn);
				}
			}
			
			for each (var numStepper:NumStepper in _numSteppers)
			{
				if (getSection(numStepper.groupeName) == _currentSection)
				{
					adjustFurnitureModelByNumStep(furn, numStepper);
				}
			}
			return furn;
		}
		
		private function setupSection(section:String):void
		{
			var updatedGroups:Vector.<String> = new Vector.<String>();
			var groupeName:String;
			var rbInfo:RadioButtonInfo;
			for each(var rb:RadioButton in _radioButtons)
			{
				if (getSection(rb.groupName) == section)
				{
					rbInfo = rb.value as RadioButtonInfo;
					if (rbInfo != null)
					{
						groupeName = rbInfo.type;
						if (updatedGroups.indexOf(groupeName) < 0)
						{
							rb.selected = true;
							updatedGroups.push(groupeName);
						}
						
					}
					
				}
			}
		}		
		
		override public function get width():Number 
		{
			return _moduleWidth;
		}
		
		override public function set width(value:Number):void 
		{
			_moduleWidth = value;
		}
		
		override public function get height():Number 
		{
			return _moduleHeight;
		}
		
		override public function set height(value:Number):void 
		{
			_moduleHeight = value;
		}
		
		private function handleError(err:String):void 
		{
			ErrorsCollector.getInstance().collectError("Module Attrib: " + err);
		}
		
		private function log(msg:String):void
		{
			Logger.log(this, msg);
		}
		
	}

}